#include "demoSprite.h"
#include "components/3D/sweety_3D_Camera.h"
#include "framework/sweety_Render.h"
#include "third-party/glfw/include/glfw3.h"

#define SHADER_PATH "Shaders/"
#define IMAGE_PATH "Resourses/images/"

namespace SW
{
    DemoSprite::DemoSprite()
    {
        float vtx[] = {
            // Positions         // Colors           // Texture Coords
            0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // Top Right
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // Bottom Right
           -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // Bottom Left
           -0.5f,  0.5f, 0.0f,   0.0f, 1.0f, 1.0f,   0.0f, 1.0f  // Top Left 
        };

        int idx[] = {  // Note that we start from 0!
        0, 1, 3, // First Triangle
        1, 2, 3  // Second Triangle
        };

        if (nullptr == m_VaoPtr)
        {
            m_VaoPtr = new VaoClass(vtx, sizeof(vtx), 8, idx, sizeof(idx), true, true);
        }

        InitShaders();

        LoadTexture();
    }

    DemoSprite::~DemoSprite()
    {
        if (m_VaoPtr)
        {
            delete m_VaoPtr;
            m_VaoPtr = nullptr;
        }
    }

    void DemoSprite::InitShaders()
    {
        m_Shader.useVertex(); m_Shader.useFragment();

        m_Shader.getVertex()->Load("", 1, SHADER_PATH "demoSpriteVert.glsl");

        m_Shader.getFragment()->Load("", 1, SHADER_PATH "demoSpriteFrag.glsl");

        // The vertex and fragment are added to the program object
        m_Shader.addVertex();
        m_Shader.addFragment();

        m_Shader.link();

        m_Shader.bindPipeline();
        m_Shader.useProgram();

        m_IsUseColor_SL = m_Shader.getUniformLocation("UseColor");
        m_IsUseUV_SL = m_Shader.getUniformLocation("isUseUV");
        m_Transform_SL = m_Shader.getUniformLocation("transform");

        m_Shader.reset();
    }

    void DemoSprite::LoadTexture()
    {
        m_Texture_1 = SW::CreateTexture(IMAGE_PATH "container.jpg");
        m_Texture_2 = SW::CreateTexture(IMAGE_PATH "awesomeface.jpg");
    }

    void DemoSprite::Render(const mat4& modelTrans)
    {
        if (nullptr == m_VaoPtr)
        {
            return;
        }

        m_Shader.bindPipeline();
        m_Shader.useProgram();

        m_VaoPtr->bindVao();

        glUniform1i(m_IsUseColor_SL, m_IsUseColor);
        glUniform1i(m_IsUseUV_SL, m_IsUseUV);

        // Bind Textures using texture units
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, (int)m_Texture_1.textureId);
        glUniform1i(m_Shader.getUniformLocation("ourTexture1"), 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, (int)m_Texture_2.textureId);
        glUniform1i(m_Shader.getUniformLocation("ourTexture2"), 1);
			
		// first container
		mat4 transform(1.0f), transMatrix(1.0f), rotateMatrix(1.0f);
        transMatrix = translate(transMatrix, vec3(0.5f, -0.5f, 0.0f));
        rotateMatrix = rotate(rotateMatrix, (GLfloat)glfwGetTime() * 5.0f, vec3(0.0f, 0.0f, 1.0f));
        transform = transMatrix * rotateMatrix;
        glUniformMatrix4fv(m_Transform_SL, 1, GL_FALSE, value_ptr(transform));        
        m_VaoPtr->draw(true);

        // second container
        mat4 transMatrix_2(1.0f), scaleMatrix(1.0f);
        transMatrix_2 = translate(transMatrix_2, vec3(-0.5f, 0.5f, 0.0f));
        GLfloat scaleAmount = sin(glfwGetTime());
        scaleMatrix = scale(scaleMatrix, vec3(scaleAmount, scaleAmount, scaleAmount));
        transform = transMatrix_2 * scaleMatrix;
        glUniformMatrix4fv(m_Transform_SL, 1, GL_FALSE, value_ptr(transform));
        m_VaoPtr->draw(true);

        // third container
        mat4 model(1.0f), model2(1.0f), view(1.0f), projection(1.0f);
        model = rotate(model, -45.0f, vec3(1.0f, 0.0f, 0.0f));
        model2 = translate(model2, vec3(0.5f, 0.5f, 0.0f));
        //view = translate(view, vec3(0.0f, 0.0f, -3.0f));
        Camera3D* camera = dynamic_cast<Camera3D*>(Renderer::GetCurrentCamera());
        if (!m_IsResetCampos)
        {
            camera->SetPos(vec3(0.f, 0.f, 3.f));
            m_IsResetCampos = true;
        }
        view = camera->GetViewTrans();
        projection = camera->GetProjectionTrans();
        transform = model2 * projection * view * model;
        glUniformMatrix4fv(m_Transform_SL, 1, GL_FALSE, value_ptr(transform));
        m_VaoPtr->draw(true);

        m_Shader.reset();
    }

    bool DemoSprite::GetUseColor() const
    {
        return m_IsUseColor;
    }

    void DemoSprite::SetUseColor(bool useColor)
    {
        m_IsUseColor = useColor;
    }

    bool DemoSprite::GetUseUV() const
    {
        return m_IsUseUV;
    }

    void DemoSprite::SetUseUV(bool useUV)
    {
        m_IsUseUV = useUV;
    }
}